package com.hsmpay.yl8583.service;

import com.hsmpay.utils.DesUtil;
import com.hsmpay.utils.WriteFile;
import com.hsmpay.yl8583.utils.TestDes;
import com.iso8583.Iso8583Composer;
import com.iso8583.Iso8583Parser;
import com.iso8583.util.ByteUtils;
import com.iso8583.util.J8583Util;
import com.iso8583.util.PosUtil;
import org.apache.commons.lang.StringUtils;
import java.util.HashMap;
import java.util.Map;

public class ZhongLanSocketToBoss {

    static WriteFile wf = new WriteFile("ds_ZhongLan");
    static String ipAddr = "218.106.246.198";
    static Integer iPort = 6002;
    String itimeout = "60000";
    String ShopCode = "810000050450001";//商户号
    String PosNo = "10000001";//终端号
    String tpdu = "6000050000";//tpdu
    String header = "603100311004";//header
    String batch = "000001";// 批次号
    String operator = "001";//操作员
    String PinKey = "";
    //封顶密文报文密钥
    String MacKey = "";
    //磁道密钥
    String trkKey = "";
    //母POS密钥
    String MasterKey = "BF582C9162E09858E58952FDA225B970";
    /**
     * 构造函数
     *
     * @param ShopCode
     * @param PosNo
     * @param batch
     * @param MasterKey
     * @param PinKey
     * @param MacKey
     * @param trkKey
     */
    public ZhongLanSocketToBoss(String ShopCode, String PosNo, String batch, String MasterKey, String PinKey, String MacKey, String trkKey, Map<String,String> config) {
        if (null != config){
            this.ipAddr = config.containsKey("ip") ? config.get("ip") : "";
            String port = config.containsKey("port") ? config.get("port") : "";
            if (StringUtils.isNotBlank(port)){
                this.iPort = Integer.valueOf(port);
            }
        }
        this.ShopCode = ShopCode;
        this.PosNo = PosNo;
        this.batch = batch;
        this.MasterKey = MasterKey;
        this.PinKey = PinKey;
        this.MacKey = MacKey;
        this.trkKey = trkKey;
        if (null != batch && StringUtils.isEmpty(batch.trim())) {
            this.batch = "000001";
        }
        wf.log("tpdu:" + this.tpdu, "调试");
        wf.log("ShopCode(商户号):" + this.ShopCode, "调试");
        wf.log("PosNo(终端号):" + this.PosNo, "调试");
        wf.log("batch(批次号):" + this.batch, "调试");
        wf.log("MasterKey:" + this.MasterKey, "调试");
        wf.log("PinKey:" + this.PinKey, "调试");
        wf.log("MacKey:" + this.MacKey, "调试");
        wf.log("trkKey:" + this.trkKey, "调试");
    }
    /**
     * 终端签到
     * @return 批次号
     * @throws Exception
     */
    public String Login0800(String serialNumber) throws Exception {
        String LoginMsg = "";
        String TYPE_ID = "0800";
        String mustFields = "";
        HashMap<String,String> body = new HashMap<String,String>();
        wf.log("-------------------请求包域值信息-------------------", "调试");
        body.put("TPDU", this.tpdu);
        body.put("HEAD", this.header);
        body.put("CSEQ_NO", serialNumber);
        body.put("TRM_NO", this.PosNo);
        body.put("MERC_CD", this.ShopCode);
        body.put("RESE_PRI_60", "00" + batch + "003");
        body.put("RESE_PRI_63", "001");

        String optionalFields = "11|41|42|60|63";
        //生成报文
        wf.log("中岚签到生成请求报文...","调试");
        Iso8583Composer composer = new Iso8583Composer();
        byte[] unMacMessage = composer.compose(mustFields, optionalFields, TYPE_ID, body, "ZHONGLAN", true);
        unMacMessage = J8583Util.getLength(unMacMessage);
        String req = ByteUtils.byte2HexStr(unMacMessage, false);//此处false代表加不加空格
        wf.log("中岚签到请求报文为：" + req, "调试");
        //发送请求报文，并且返回响应
        byte[] response = PosUtil.sendPosMsg(unMacMessage, this.ipAddr, this.iPort);
        String res = ByteUtils.byte2HexStr(response, false);
        wf.log("中岚签到响应报文为：" + res, "调试");
        try {
            //解析报文
            byte[] bytes = ByteUtils.hexStringToByte(res);
            Map<String, String> map = Iso8583Parser.parse("ZHONGLAN", bytes, true);
            String bit39 = map.get("39");
            String bit60 = map.get("60").substring(2,8);
            String bit62 = map.get("62");
            if (StringUtils.isBlank(bit60)) {
                bit60 = "000001";
            }
            if (StringUtils.isBlank(bit62)){
                LoginMsg = "-1_";
                return LoginMsg;
            }else if (bit62.length() != 80){
                LoginMsg = "-1_";
                wf.log("签到返回的报文长度不正确","调试");
                return LoginMsg;
            }
            String PIK = bit62.substring(0,32);
            String PIK_CHECKVALUE = bit62.substring(32,40);
            String MAK = bit62.substring(40,72);
            String MAK_CHECKVALUE = bit62.substring(72);
            String decodedPIK = DesUtil.decode3DES(PIK, MasterKey);
            String decodedMAK = DesUtil.decode3DES(MAK, MasterKey);
            String PIK_CHECK = DesUtil.encrypt3DES("0000000000000000", decodedPIK).substring(0,8);
            String MAK_CHECK = DesUtil.byte2hex(DesUtil.encryptDES(DesUtil.hexStringToByte(decodedMAK),DesUtil.hexStringToByte("0000000000000000"))).substring(0,8);
            System.out.println("PIK校验结果为: " + PIK_CHECKVALUE.equals(PIK_CHECK));
            System.out.println("MAK校验结果为: " + MAK_CHECKVALUE.equals(MAK_CHECK));
            LoginMsg = "0_"+ bit39+ "_" + bit60 + "_" + PIK + "_" + MAK;
        }catch (Exception e) {
            e.printStackTrace();
            wf.log("中岚签到返回报文解析错误" ,"调试");
            LoginMsg = "-1_";
        }
        return LoginMsg;
    }
    /**
     * 银行卡余额查询
     * @param trk2 二磁道数据
     * @param trk3 二磁道数据
     * @param pin  卡交易密码
     * @param accountNumber 主账号
     * @param serialNumber 受卡方系统跟踪号
     * @return 订单信息
     * @throws Exception
     */
    public String Query(String trk2, String trk3, String pin, String accountNumber, String serialNumber, String bit23, String bit55, String bit14) throws Exception {
        String des_pin = TestDes.MakeDesPin(accountNumber, pin, PinKey, MasterKey);
        String QueryMsg = "";
        String TYPE_ID = "0200";
        String mustFields = "";
        StringBuffer optionalFields = new StringBuffer("");
        HashMap<String,String> body = new HashMap<String,String>();
        wf.log("-------------------请求包域值信息-------------------", "调试");
        body.put("TPDU", this.tpdu);
        body.put("HEAD", this.header);
        body.put("PRO_COD", "310000");
        optionalFields.append("3|");
        body.put("CSEQ_NO", serialNumber);
        optionalFields.append("11|");
        if (!"".equals(bit14.trim())) {
            body.put("EXP_DT", bit14);
            optionalFields.append("14|");
        }
        if ("".equals(bit55.trim())) {
            body.put("IN_MOD", "021");
            optionalFields.append("22|");
        }else {
            body.put("IN_MOD", "051");
            optionalFields.append("22|");
        }
        if (!"".equals(bit23.trim())) {
            body.put("SEP_NUM", bit23);
            optionalFields.append("23|");
        }
        body.put("CON_MOD", "00");
        optionalFields.append("25|");
        body.put("PIN_CAP_CODE", "12");
        optionalFields.append("26|");
        if (!"".equals(trk2.trim())) {
            body.put("TRACK_2", trk2);
            optionalFields.append("35|");
        }
        if (!"".equals(trk3.trim())) {
            body.put("TRACK_3", trk3);
            optionalFields.append("36|");
        }
        body.put("TRM_NO", this.PosNo);
        optionalFields.append("41|");
        body.put("MERC_CD", this.ShopCode);
        optionalFields.append("42|");
        body.put("CCY", "156");
        optionalFields.append("49|");
        body.put("PIN_DATA", des_pin);
        optionalFields.append("52|");
        body.put("SECUR_INF", "2600000000000000");
        optionalFields.append("53|");
        if (!"".equals(bit55.trim())) {
            body.put("IC_DAT", bit55);
            optionalFields.append("55|");
        }
        body.put("RESE_PRI_60", "01" + this.batch);
        optionalFields.append("60|");
        optionalFields.append("64");
        body.put("F64","");
        Iso8583Composer com = new Iso8583Composer();
        byte[] MacMessage = com.compose(mustFields, optionalFields.toString(), TYPE_ID, body, "ZHONGLAN", true);
        String request = ByteUtils.byte2HexStr(MacMessage,false);
        String sub = request.substring(22, request.length()-16);
        String macstr = TestDes.MakeZhongLanECBMac(MacKey, sub, MasterKey);//加密操作,传参问题
        body.put("F64", macstr);
        //生成报文
        Iso8583Composer composer = new Iso8583Composer();
        byte[] unMacMessage = composer.compose(mustFields, optionalFields.toString(), TYPE_ID, body, "ZHONGLAN", true);
        unMacMessage = J8583Util.getLength(unMacMessage);
        String req = ByteUtils.byte2HexStr(unMacMessage,false);//此处false代表加不加空格
        wf.log("中岚查询余额请求报文为：" + req, "调试");
        byte[] response = PosUtil.sendPosMsg(unMacMessage, ipAddr, iPort);
        String res = ByteUtils.byte2HexStr(response, false);
        if ((!"-1".equals(res)) && (!"".equals(res))) {
            wf.log("中岚查询余额响应报文为：" + res, "调试");
            try {
                PosUtil.parse8583("ZHONGLAN", res);
                //解析报文
                Map<String, String> map = Iso8583Parser.parse("ZHONGLAN", response, true);
                //获取39、54域
                String result39 = map.get("39");
                if ("00".equals(result39)){
                    String result54 = map.get("54");
                    String AmountStr = handle54(result54);
                    QueryMsg = "0" + "_" + result39 + "_" + AmountStr;
                }else {
                    QueryMsg = "0" + "_" + result39;
                }
            }catch (Exception e) {
                e.printStackTrace();
                wf.log("中岚查询余额解析错误", "调试");
            }
        }else {
            QueryMsg = "-1_";
        }
        wf.log("中岚佘额查询返回数据:" + QueryMsg, "调试");
        return QueryMsg;
    }
    /**
     * 处理54域信息的方法
     */
    public String  handle54(String field54){
        String ACCOUNT_TYPE="";		//帐户类型(10:储蓄帐户,30:信用卡帐户)
        String CURRENCY_CODE="";	//货币代码(156:人民币,其它:美元)
        String AMOUNT_SIGN="";		//余额符号(C:正,其它:负)
        Double AMOUNT=0.00;			//佘额(12位表示,分为单位)
        String AmountStr="";
        ACCOUNT_TYPE=field54.substring(0, 2);
        CURRENCY_CODE=field54.substring(4,7);
        AMOUNT_SIGN=field54.substring(7, 8);
        AMOUNT=Double.parseDouble(field54.substring(8))/100;
        if(ACCOUNT_TYPE.equals("10"))
        {
            AmountStr+="储蓄帐户 ";
        }else if(ACCOUNT_TYPE.equals("30"))
        {
            AmountStr+="信用卡帐户 ";
        }
        if(CURRENCY_CODE.equals("156"))
        {
            AmountStr+="￥";
        }else{
            AmountStr+="$";
        }
        if(!AMOUNT_SIGN.equals("C"))
        {
            AmountStr+="-";
        }
        AmountStr+=AMOUNT;
        return AmountStr;
    }
    /**
     * 消费
     *
     * @param trk2          二磁道数据
     * @param trk3          三磁道数据
     * @param pin           密码
     * @param money         交易金额
     * @param accountNumber 卡号
     * @param serialNumber  订单号
     * @param bit23         IC卡序列号
     * @param bit55         IC卡 55 域
     * @param bit14         IC卡 序列号
     * @return 返回消费相关信息
     * @throws Exception
     */
    public String BillPayment(String trk2, String trk3, String pin, String money, String accountNumber, String serialNumber, String bit23, String bit55, String bit14, Long userid) throws Exception {
        String des_pin = TestDes.MakeDesPin(accountNumber, pin, PinKey, MasterKey);
        String comsumeMsg = "";
        String TYPE_ID = "0200";
        String mustFields = "";
        StringBuffer optionalFields = new StringBuffer("");
        HashMap<String,String> body = new HashMap<String,String>();
        wf.log("-------------------请求包域值信息-------------------", "调试");
        body.put("TPDU", this.tpdu);
        body.put("HEAD", this.header);
        body.put("PAN", accountNumber);
        optionalFields.append("2|");
        body.put("PRO_COD", "000000");
        optionalFields.append("3|");
        body.put("TTXN_AMT", money);
        optionalFields.append("4|");
        body.put("CSEQ_NO", serialNumber);
        optionalFields.append("11|");
        if (!"".equals(bit14.trim())) {
            body.put("EXP_DT", bit14);
            optionalFields.append("14|");
        }
        if ("".equals(bit55.trim())) {
            body.put("IN_MOD", "021");
            optionalFields.append("22|");
        }else {
            body.put("IN_MOD", "051");
            optionalFields.append("22|");
        }
        if (!"".equals(bit23.trim())) {
            body.put("SEP_NUM", bit23);
            optionalFields.append("23|");
        }
        body.put("CON_MOD", "00");
        optionalFields.append("25|");
        body.put("PIN_CAP_CODE", "06");
        optionalFields.append("26|");
        if (!"".equals(trk2.trim())) {
            body.put("TRACK_2", trk2);
            optionalFields.append("35|");
        }
        if (!"".equals(trk3.trim())) {
            body.put("TRACK_3", trk3);
            optionalFields.append("36|");
        }
        body.put("TRM_NO", this.PosNo);
        optionalFields.append("41|");
        body.put("MERC_CD", this.ShopCode);
        optionalFields.append("42|");
        body.put("CCY", "156");
        optionalFields.append("49|");
        body.put("PIN_DATA", des_pin);
        optionalFields.append("52|");
        if (!"".equals(bit55.trim())) {
            body.put("IC_DAT", bit55);
            optionalFields.append("55|");
        }
        if ("".equals(bit55.trim())) {
            body.put("RESE_PRI_60", "22" + this.batch);
            optionalFields.append("60|");
        }else {
            body.put("RESE_PRI_60", "22" + this.batch + "0005");
            optionalFields.append("60|");
        }
        optionalFields.append("64");
        body.put("F64","");
        Iso8583Composer com = new Iso8583Composer();
        byte[] MacMessage = com.compose(mustFields, optionalFields.toString(), TYPE_ID, body, "ZHONGLAN", true);
        String request = ByteUtils.byte2HexStr(MacMessage,false);
        String sub = request.substring(22, request.length()-16);
        //63域是否要出现
        String macstr = TestDes.MakeZhongLanECBMac(MacKey, sub, MasterKey);//加密操作,传参问题
        body.put("F64", macstr);
        //生成报文
        Iso8583Composer composer = new Iso8583Composer();
        byte[] unMacMessage = composer.compose(mustFields, optionalFields.toString(), TYPE_ID, body, "ZHONGLAN", true);
        unMacMessage = J8583Util.getLength(unMacMessage);
        String req = ByteUtils.byte2HexStr(unMacMessage,false);//此处false代表加不加空格
        PosUtil.parse8583("ZHONGLAN",req.substring(4));//解析请求报文
        wf.log("中岚消费请求报文为：" + req, "调试");
        //发送请求报文，并且返回响应
        byte[] response = PosUtil.sendPosMsg(unMacMessage, ipAddr, iPort);
        String res = ByteUtils.byte2HexStr(response, false);
        wf.log("中岚消费响应报文为：" + res, "调试");
        try {
            PosUtil.parse8583("ZHONGLAN", res);
            //解析报文,返回解析的域map
            Map<String, String> map = Iso8583Parser.parse("ZHONGLAN", response, true);
            //需要获取2,4,11,12,13,14,37,38,39域信息
            String result2 = map.get("2");
            String result4 = map.get("4");
            String result11 = map.get("11");
            String result12 = map.get("12");
            String result13 = map.get("13");
            String result14 = map.get("14");
            String result37 = map.get("37");
            String result38 = map.get("38");
            String result39 = map.get("39");
            comsumeMsg = "0_" + result2 + "_" +result4 + "_" +result11 + "_" + result12 + "_" +result13 + "_" + result14 + "_" +result37 + "_" +result38 +"_"+result39;
        }catch (Exception e) {
            e.printStackTrace();
            wf.log("中岚消费响应报文解析错误", "调试");
            comsumeMsg = "-1_";
        }
        wf.log("中岚消费返回数据:" + comsumeMsg, "调试");
        return comsumeMsg;
    }

    /**
     * 消费冲正（交易）
     * @return 订单信息
     * @throws Exception
     */
    public String unBillPayment(String money,String accountNumber,String serialNumber,String bit39,String bit38,String bit23,String bit55,String bit14) throws Exception {

        String QueryMsg = "";
        String typeCode = "0400";//消息类型
        String mustFields = "";
        StringBuffer optinalFields = new StringBuffer("");
        HashMap<String, String> body = new HashMap<String, String>();
        body.put("TPDU", this.tpdu);
        body.put("HEAD",this.header);
        body.put("PAN", accountNumber);
        optinalFields.append("2|");//添加2域
        body.put("PRO_COD", "000000");//交易处理码 3 跟原交易相同
        optinalFields.append("3|");
        body.put("TTXN_AMT", money);//交易金额 4  跟原交易相同
        optinalFields.append("4|");
        body.put("CSEQ_NO", serialNumber); //受卡方系统跟踪号 同原交易
        optinalFields.append("11|");
        if (!"".equals(bit14)){
            body.put("EXP_DT", bit14);
            optinalFields.append("14|");
        }
        if ("".equals(bit55.trim())) {//服务点输入方式码 22 跟原交易相同
            body.put("IN_MOD", "021");
            optinalFields.append("22|");
        }else {
            body.put("IN_MOD", "051");
            optinalFields.append("22|");
        }
        if (!"".equals(bit23)){
            body.put("SEP_NUM", bit23);
            optinalFields.append("23|");
        }
        body.put("CON_MOD", "00");//服务点条件码 25
        optinalFields.append("25|");
        //38域需要判断应答码中是否存在
        if (StringUtils.isNotBlank(bit38)){
            body.put("AUT_CD", bit38);//授权标识应答码 38 如果原始交易的应答中有授权码，则须填入原交易授权码 从响应报文中获取
            optinalFields.append("38|");
        }
        body.put("CPSCOD",bit39);//应答码 39 请求时为冲正原因，见注  交易报文中获取
        optinalFields.append("39|");
        body.put("TRM_NO", this.PosNo);//受卡机终端标识码 41 同原消费交易
        optinalFields.append("41|");
        body.put("MERC_CD", this.ShopCode);//受卡方标识码 42
        optinalFields.append("42|");
        body.put("CCY", "156");//交易货币代码 49
        optinalFields.append("49|");
        if (!"".equals(bit55)){
            body.put("IC_DAT",bit55);
            optinalFields.append("55|");
        }
        if ("".equals(bit55)) {
            body.put("RESE_PRI_60", "22" + this.batch);
            optinalFields.append("60|");
        }else {
            body.put("RESE_PRI_60", "22" + this.batch + "0005");
            optinalFields.append("60|");
        }
        optinalFields.append("64");
        body.put("F64", "");
        Iso8583Composer com = new Iso8583Composer();
        byte[] MacMessage = com.compose(mustFields, optinalFields.toString(), typeCode, body, "ZHONGLAN", true);
        String request = ByteUtils.byte2HexStr(MacMessage,false);
        String sub = request.substring(22, request.length() - 16);
        String macstr = TestDes.MakeZhongLanECBMac(MacKey, sub, MasterKey);//加密操作,传参问题
        body.put("F64", macstr);
        //生成报文
        Iso8583Composer composer = new Iso8583Composer();
        byte[] unMacMessage = composer.compose(mustFields, optinalFields.toString(), typeCode, body, "ZHONGLAN", true);
        unMacMessage = J8583Util.getLength(unMacMessage);
        String req = ByteUtils.byte2HexStr(unMacMessage,false);//此处false代表加不加空格
        wf.log("中岚消费冲正请求报文为：" + req, "调试");
        //发送请求报文，并且返回响应
        byte[] response = PosUtil.sendPosMsg(unMacMessage, ipAddr, iPort);
        String res = ByteUtils.byte2HexStr(response, false);
        wf.log("中岚消费冲正响应报文为：" + res, "调试");
        try {
            PosUtil.parse8583("ZHONGLAN", res);
            //解析报文
            byte[] bytes = ByteUtils.hexStringToByte(res);
            Map<String, String> map = Iso8583Parser.parse("ZHONGLAN", bytes, true);
            String temp2 = map.get("2");
            String temp4 = map.get("4");
            String temp11 = map.get("11");
            String temp12 = map.get("12");
            String temp13 = map.get("13");
            String temp14 = map.get("14");
            String temp37 = map.get("37");
            String temp38 = map.get("38");
            String temp39 = map.get("39");
            String temp44 = map.get("44");
            QueryMsg = "0_"+temp2+"_"+temp4+"_"+temp11+"_"+temp12+"_"+temp13+"_"+temp14+"_"+temp37+"_"+temp38+"_"+temp39+"_"+temp44;
        }catch (Exception e) {
            e.printStackTrace();
            wf.log("中岚消费冲正响应报文解析错误", "调试");
            QueryMsg = "-1_";
        }
        wf.log("中岚消费冲正返回数据:" + QueryMsg, "调试");
        return QueryMsg;
    }
}
